home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rules / prs2 / prs2view.c < prev   
Encoding:
C/C++ Source or Header  |  1992-08-27  |  10.0 KB  |  319 lines

  1. /*========================================================================
  2.  *
  3.  * IDENTIFICATION:
  4.  *     $Header: /private/postgres/src/rules/prs2/RCS/prs2view.c,v 1.12 1991/11/18 22:21:22 mer Exp $
  5.  *
  6.  * DESCRIPTION:
  7.  * This file contains (among other things!) the code for 'view-like' rules,
  8.  * i.e. rules that return many tuples at a time like:
  9.  *    ON retrieve to <relation>
  10.  *      DO [ instead ] retrieve ......
  11.  *
  12.  * (if we specify a 'instead' then this is a virtual view,
  13.  * otherwise it might be partially materialized)
  14.  *
  15.  *
  16.  *========================================================================
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include "utils/log.h"
  21. #include "executor/execdefs.h"
  22. #include "rules/prs2locks.h"
  23. #include "rules/prs2.h"
  24. #include "rules/prs2stub.h"
  25. #include "nodes/execnodes.h"
  26. #include "parser/parse.h"    /* for RETRIEVE, APPEND etc. */
  27. #include "utils/palloc.h"
  28.  
  29. extern EState CreateExecutorState();
  30. extern LispValue ExecMain();
  31.  
  32. /*-----------------------------------------------------------------------
  33.  * prs2MakeRelationRuleInfo(relation)
  34.  *
  35.  * This initializes some information about the rules affecting a
  36.  * relation.
  37.  *
  38.  * There are 2 places where this routine can be called:
  39.  *
  40.  * A) by 'ExecInitSeqScan' and 'ExecInitIndexScan'
  41.  * when the 'ScanState' of a 'Scan' node is intialized.
  42.  * In this case `operation' must be RETRIEVE
  43.  *
  44.  * B) by InitPlan when we have an update plan (i.e. a delete, append
  45.  * or a replace command). In this case the 'operation' must be
  46.  * APPEND, DELETE or REPLaCE.
  47.  * 
  48.  * This scan state contains among other things some information
  49.  * needed by the rule manager. See commnets in the definition of the
  50.  * 'RelationRuleInfo' struct for more details....
  51.  *
  52.  */
  53. RelationRuleInfo
  54. prs2MakeRelationRuleInfo(relation, operation)
  55. Relation relation;
  56. int operation;
  57. {
  58.     RuleLock locks;
  59.     Name relationName;
  60.     int i, j, nlocks;
  61.     Prs2OneLock oneLock;
  62.     Prs2LockType lockType;
  63.     ObjectId ruleId;
  64.     Prs2PlanNumber planNo;
  65.     long size;
  66.     int nrules;
  67.     Prs2RuleList  ruleList, ruleListItem;
  68.     Prs2Stub stubs;
  69.     RelationRuleInfo relationRuleInfo;
  70.  
  71.  
  72.     /*
  73.      * find the locks of the relation...
  74.      */
  75.     relationName = RelationGetRelationName(relation);
  76.     locks = prs2GetLocksFromRelation(relationName);
  77.  
  78.     /*
  79.      * create a linked list of all the rule ids that hold a
  80.      * 'LockTypeRetrieveRelation'
  81.      */
  82.     ruleList = NULL;
  83.     if (operation == RETRIEVE) {
  84.     nlocks = prs2GetNumberOfLocks(locks);
  85.     for (i=0; i<nlocks ; i++) {
  86.         oneLock = prs2GetOneLockFromLocks(locks, i);
  87.         lockType = prs2OneLockGetLockType(oneLock);
  88.         ruleId = prs2OneLockGetRuleId(oneLock);
  89.         planNo = prs2OneLockGetPlanNumber(oneLock);
  90.         if (lockType==LockTypeRetrieveRelation) {
  91.         ruleListItem = (Prs2RuleList) palloc(sizeof(Prs2RuleListItem));
  92.         if (ruleListItem == NULL) {
  93.             elog(WARN,"prs2MakeRuleList: Out of memory");
  94.         }
  95.         ruleListItem->type = PRS2_RULELIST_RULEID;
  96.         ruleListItem->data.ruleId.ruleId = ruleId;
  97.         ruleListItem->data.ruleId.planNumber = planNo;
  98.         ruleListItem->next = ruleList;
  99.         ruleList = ruleListItem;
  100.         }
  101.     }
  102.     }
  103.  
  104.     /*
  105.      * now find the relation level rule stubs.
  106.      */
  107.     stubs = prs2GetRelationStubs(RelationGetRelationId(relation));
  108.  
  109.     /*
  110.      * Create and return a 'RelationRuleInfo' structure..
  111.      */
  112.     size = sizeof(RelationRuleInfoData);
  113.     relationRuleInfo = (RelationRuleInfo) palloc(size);
  114.     if (relationRuleInfo == NULL) {
  115.     elog(WARN,
  116.         "prs2MakeRelationRuleInfo: Out of memory! (%ld bytes requested)",
  117.         size);
  118.     }
  119.  
  120.     relationRuleInfo->ruleList = ruleList;
  121.     relationRuleInfo->insteadViewRuleFound = false;
  122.     relationRuleInfo->relationLocks = locks;
  123.     relationRuleInfo->relationStubs = stubs;
  124.     relationRuleInfo->relationStubsHaveChanged = false;
  125.  
  126.     /*
  127.      * if this is the "pg_class" then ignore all tuple level locks
  128.      * found in tuples, because these locks are not "real" tuple level
  129.      * locks of rules defined in "pg_class", but they are relation level
  130.      * locks defined on various other relations.
  131.      */
  132.     if (!strcmp(relationName, Name_pg_relation))
  133.     relationRuleInfo->ignoreTupleLocks = true;
  134.     else
  135.     relationRuleInfo->ignoreTupleLocks = false;
  136.  
  137.     return(relationRuleInfo);
  138.  
  139. }
  140.  
  141. /*-----------------------------------------------------------------------
  142.  *
  143.  * prs2GetOneTupleFromViewRules
  144.  */
  145. HeapTuple
  146. prs2GetOneTupleFromViewRules(relationRuleInfo, prs2EStateInfo, relation,
  147.                 explainRel)
  148. RelationRuleInfo relationRuleInfo;
  149. Prs2EStateInfo prs2EStateInfo;
  150. Relation relation;
  151. Relation explainRel;
  152. {
  153.  
  154.     long size;
  155.     Prs2RuleList tempRuleList, tempRuleListItem;
  156.     ParamListInfo paramList;
  157.     LispValue plan, ruleInfo, planQual, planActions, onePlan;
  158.     LispValue queryDesc;
  159.     EState executorState;
  160.     LispValue res;
  161.     HeapTuple tuple;
  162.  
  163.  
  164.     /*
  165.      * Process the first record of 'ruleList',
  166.      * until either the lsit becomes empty, or
  167.      * a new tuple is created....
  168.      */
  169.     while(relationRuleInfo->ruleList != NULL) {
  170.     switch (relationRuleInfo->ruleList->type) {
  171.         case PRS2_RULELIST_RULEID:
  172.         /*
  173.          * Fetch the plan from Prs2PlansRelation.
  174.          */
  175.         plan = prs2GetRulePlanFromCatalog(
  176.                 relationRuleInfo->ruleList->data.ruleId.ruleId,
  177.                 relationRuleInfo->ruleList->data.ruleId.planNumber,
  178.                 ¶mList);
  179.         /*
  180.          * It is possible that plan = nil (an obsolete rule?)
  181.          * In this case ignore the rule.
  182.          */
  183.         if (null(plan)) {
  184.             break;
  185.         }
  186.         /*
  187.          * NOTE: the `paramList' must be empty!
  188.          * because we do not allow 'NEW' & 'OLD' in 'view-like' rules.
  189.          * Note though, that the rule qualification might not
  190.          * be empty. E.g. it might be something like:
  191.          *       where user() == "Spyros the Great"
  192.          */
  193.         if (paramList != NULL && paramList[0].kind != PARAM_INVALID) {
  194.             elog(WARN, "View Rules must not have parameters!\n");
  195.         }
  196.         ruleInfo = prs2GetRuleInfoFromActionPlan(plan);
  197.         planQual = prs2GetQualFromActionPlan(plan);
  198.         planActions = prs2GetActionsFromActionPlan(plan);
  199.         /*
  200.          * test the rule qualification and if true, then
  201.          * for every plan specified in the action part of the
  202.          * rule, create a Prs2RuleListItem and insert it
  203.          * in a linked list.
  204.          */
  205.         if (prs2CheckQual(planQual, paramList, prs2EStateInfo)) {
  206.             tempRuleList = relationRuleInfo->ruleList->next;
  207.             foreach(onePlan, planActions) {
  208.             size = sizeof(Prs2RuleListItem);
  209.             tempRuleListItem = (Prs2RuleList) palloc(size);
  210.             if (tempRuleListItem == NULL) {
  211.                 elog(WARN,
  212.                 "prs2GetOneTupleFromViewRules: Out of memory");
  213.             }
  214.             tempRuleListItem->type = PRS2_RULELIST_PLAN;
  215.             tempRuleListItem->data.rulePlan.plan = CAR(onePlan);
  216.             tempRuleListItem->next = tempRuleList;
  217.             tempRuleList = tempRuleListItem;
  218.             }
  219.             /*
  220.              * no more action plans for this rule.
  221.              * replace the Prs2RuleListItem of theis rule with
  222.              * the chain of Prs2RuleListItem(s) we have just
  223.              * created.
  224.              */
  225.             tempRuleListItem = relationRuleInfo->ruleList;
  226.             relationRuleInfo->ruleList = tempRuleList;
  227.             pfree((Pointer)tempRuleListItem);
  228.             /*
  229.              * check for 'instead' rules...
  230.              */
  231.             if (prs2IsRuleInsteadFromRuleInfo(ruleInfo)) {
  232.             relationRuleInfo->insteadViewRuleFound = true;
  233.             }
  234.         }
  235.         break;
  236.         case PRS2_RULELIST_PLAN:
  237.         /*
  238.          * this is a rule plan. COnstruct the query descriptor,
  239.          * the EState, and call the executor to perform the
  240.          * EXEC_START operation...
  241.          */
  242.         queryDesc = prs2MakeQueryDescriptorFromPlan(
  243.                 relationRuleInfo->ruleList->data.rulePlan.plan);
  244.         executorState = CreateExecutorState();
  245.         set_es_param_list_info(executorState, paramList);
  246.         set_es_prs2_info(executorState, prs2EStateInfo);
  247.         ExecMain(queryDesc, executorState,
  248.             lispCons(lispInteger(EXEC_START), LispNil));
  249.         size = sizeof(Prs2RuleListItem);
  250.         tempRuleList = (Prs2RuleList) palloc(size);
  251.         if (tempRuleList == NULL) {
  252.             elog(WARN,
  253.             "prs2GetOneTupleFromViewRules: Out of memory");
  254.         }
  255.         tempRuleList->type = PRS2_RULELIST_QUERYDESC;
  256.         tempRuleList->data.queryDesc.queryDesc = queryDesc;
  257.         /*
  258.          * NOTE: the following typecast is due to a stupid
  259.          * circular dependency in the definitions of `EState' and
  260.          * `Prs2RuleList' which obliged me to declare 
  261.          * `Prs2RuleList->data.queryDesc.estate' not as an `EState'
  262.          * (which is the correct) but as a (struct *). Argh!
  263.          */
  264.         tempRuleList->data.queryDesc.estate = (Pointer) executorState;
  265.         tempRuleList->next = relationRuleInfo->ruleList->next;
  266.         tempRuleListItem = relationRuleInfo->ruleList;
  267.         relationRuleInfo->ruleList = tempRuleList;
  268.         pfree((Pointer)tempRuleListItem);
  269.         break;
  270.         case PRS2_RULELIST_QUERYDESC:
  271.         /*
  272.          * At last! a query desciptor (and an EState!)
  273.          * properly initialized...
  274.          * Call exec main to retrieve a tuple...
  275.          */
  276.         res = ExecMain(
  277.             relationRuleInfo->ruleList->data.queryDesc.queryDesc,
  278.             relationRuleInfo->ruleList->data.queryDesc.estate,
  279.             lispCons(lispInteger(EXEC_RETONE), LispNil));
  280.         tuple = (HeapTuple) ExecFetchTuple((TupleTableSlot)res);
  281.         if (tuple != NULL) {
  282.             /*
  283.              * Yeahhh! the executor returned a tuple!
  284.              *
  285.              * Make a COPY of this tuple
  286.              * we need to make a copy for 2 reasons:
  287.              * a) the (low level) executor might release it when
  288.              *    called with EXEC_END
  289.              * b) the top level executor might want to pfree it
  290.              *    and pfree seems to complain (I guess something
  291.              *    to do with the fact that this palloc happenned
  292.              *    in the lower executor's context and not in
  293.              *    the current one...
  294.              */
  295.             tuple = palloctup(tuple, InvalidBuffer, relation);
  296.             return(tuple);
  297.         }
  298.         /*
  299.          * No more tuples! Remove this record from the
  300.          * relationRuleInfo->ruleList.
  301.          * But before doing that, be nice and gracefully
  302.          * let the executor release whatever it has to...
  303.          */
  304.         ExecMain(relationRuleInfo->ruleList->data.queryDesc.queryDesc,
  305.                 relationRuleInfo->ruleList->data.queryDesc.estate,
  306.                 lispCons(lispInteger(EXEC_END), LispNil));
  307.         tempRuleList = relationRuleInfo->ruleList;
  308.         relationRuleInfo->ruleList = relationRuleInfo->ruleList->next;
  309.         pfree((Pointer)tempRuleList);
  310.         break;
  311.     } /* switch */
  312.     } /* while */
  313.  
  314.     /*
  315.      * No (more) rules found, return NULL
  316.      */
  317.     return(NULL);
  318. }
  319.